package Util;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;


public class PriorSafeQueue {
	public enum Priority
	{
		Lowest(0),
		Low(1),
		Medium(2),
		High(3),
		Highest(4),
		MAX(5);
		
		private final int value_; 
		Priority(int value)
		{
			value_ = value;
		}
		public int getValue()
		{
			return value_;
		}
	}
	
	private List< Queue<Object> > safeQueueList_;
	private Lock lock_;
	private Condition condition_;
	private int waitGetThreadNum_;
	
	public PriorSafeQueue()
	{
		lock_ = new ReentrantLock(false);
		condition_ = lock_.newCondition();
		
		waitGetThreadNum_ = 0;
		
		safeQueueList_ = new ArrayList< Queue<Object> >();
		for (int i = 0 ;i < Priority.MAX.getValue();i++)
		{
			Queue<Object> aQueue = new LinkedList<Object>();
			safeQueueList_.add(aQueue);
		}
	}
	
	public void put(Object obj, Priority prior)
	{
		lock_.lock();
		{
			safeQueueList_.get(prior.getValue()).offer(obj);
			if (waitGetThreadNum_>0)
				condition_.signal();
			Config.logger.debug("Put Object["+obj.toString()+"] in "+prior.toString());
		}
		lock_.unlock();
	}
	
	public void put(Object obj)
	{
		lock_.lock();
		{
			safeQueueList_.get(Priority.Medium.getValue()).offer(obj);
			if (waitGetThreadNum_>0)
				condition_.signal();
			Config.logger.debug("Put Object["+obj.toString()+"] in "+Priority.Medium.toString());
		}
		lock_.unlock();
	}
	
	public Object get() throws InterruptedException
	{
		Object ret = null;
		lock_.lock();
		while (ret==null)
		{
			for (int i = Priority.MAX.getValue()-1;i>=0;i--)
			{
				if (!safeQueueList_.get(i).isEmpty())
				{
					ret = safeQueueList_.get(i).poll();
					break;
				}
			}
			if (ret==null)
			{
				waitGetThreadNum_++;
				condition_.await();
				waitGetThreadNum_--;
			}
		}
		lock_.unlock();
		Config.logger.debug("Get Object["+ret.toString()+"] ");
		return ret;
	}
	
	public Boolean isEmpty()
	{
		Boolean ret = true;
		lock_.lock();
		{
			for (int i = 0 ;i < Priority.MAX.getValue();i++)
				ret = ret&safeQueueList_.get(i).isEmpty();
		}
		lock_.unlock();
		return ret;
	}
}
